#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include "Log.h"

#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/cfg/env.h"

SpdLog spdLog;

std::shared_ptr<spdlog::logger> logger;

SpdLog::SpdLog()
{
    logger = NULL;
}

void SpdLog::init(int mode, const char *logger_name, const char *filename)
{
    char *env_mode = NULL;
    char *env_filename = NULL;
    char *mode_string = NULL;
    if(!logger) {
        //优先使用环境变量中的mode和file
        env_mode = getenv("SPDLOG_MODE");
        if(env_mode) {
            if(!strcmp(env_mode, "stdout")) 
                mode = SPDLOG_MODE_STDOUT;
            if(!strcmp(env_mode, "basicfile"))
                mode = SPDLOG_MODE_BASICFILE;
            if(!strcmp(env_mode, "rotafile"))
                mode = SPDLOG_MODE_ROTAFILE;
        }
        
        if(mode == SPDLOG_MODE_BASICFILE || mode == SPDLOG_MODE_ROTAFILE) {
            env_filename = getenv("SPDLOG_FILENAME");
            if(env_filename)
                filename = env_filename;
        }

        if(!logger_name)
            logger_name = "spdlog";
        if(!filename)
            mode = SPDLOG_MODE_STDOUT;

        if(mode == SPDLOG_MODE_STDOUT)
            mode_string = "stdout";
        if(mode == SPDLOG_MODE_BASICFILE)
            mode_string = "basicfile";
        if(mode == SPDLOG_MODE_ROTAFILE)
            mode_string = "rotafile";

        printf("[%s:%d:%s] env_mode:%s env_filename:%s mode:%s(%d) filename:%s logger_name:%s\n", \
            __FILENAME__ , __LINE__, __FUNCTION__, env_mode, env_filename, mode_string, mode, filename, logger_name);

        if(mode & SPDLOG_MODE_STDOUT)
            logger = spdlog::stdout_color_mt(logger_name);
        if((mode & SPDLOG_MODE_BASICFILE) && filename)
            logger = spdlog::basic_logger_mt(logger_name, filename);
        if((mode & SPDLOG_MODE_ROTAFILE) && filename)
            logger = spdlog::rotating_logger_mt(logger_name, filename, 1024 * 1024 * 5, 3);

        logger->set_pattern("%Y-%m-%d %H:%M:%S.%e %P %t %7l %v");
        logger->set_level(spdlog::level::err);
        // trigger flush if the log severity is warn or higher
        logger->flush_on(spdlog::level::warn);
    }
}

void SpdLog::setLevel(int level)
{
    if(!logger)
        return;
    int lev;
    switch(level) {
        case SPDLOG_LEVEL_TRACE:
            lev = spdlog::level::trace;
            break;
        case SPDLOG_LEVEL_DEBUG:
            lev = spdlog::level::debug;
            break;
        case SPDLOG_LEVEL_INFO:
            lev = spdlog::level::info;
            break;
        case SPDLOG_LEVEL_WARN:
            lev = spdlog::level::warn;
            break;
        case SPDLOG_LEVEL_ERROR:
            lev = spdlog::level::err;
            break;
        default:
            lev = spdlog::level::err;
    }
    logger->set_level(lev);
    loadEnvLevel();
}

//export SPDLOG_LEVEL=trace.....
void SpdLog::loadEnvLevel()
{
    if(!logger)
        return;
    spdlog::cfg::load_env_levels(); 
}

void SpdLog::e(const char *format, ...)
{
    if(!logger)
        return;
    char logbuf[2048];
    va_list ap;
    va_start(ap, format);
    vsprintf(logbuf, format, ap);
    va_end(ap);
    logger->error("{}", logbuf);
}

void SpdLog::w(const char *format, ...)
{
    if(!logger)
        return;
    char logbuf[2048];
    va_list ap;
    va_start(ap, format);
    vsprintf(logbuf, format, ap);
    va_end(ap);
    logger->warn("{}", logbuf);
}

void SpdLog::d(const char *format, ...)
{
    if(!logger)
        return;
    char logbuf[2048];
    va_list ap;
    va_start(ap, format);
    vsprintf(logbuf, format, ap);
    va_end(ap);
    logger->debug("{}", logbuf);
}

void SpdLog::i(const char *format, ...)
{
    if(!logger)
        return;
    char logbuf[2048];
    va_list ap;
    va_start(ap, format);
    vsprintf(logbuf, format, ap);
    va_end(ap);
    logger->info("{}", logbuf);
}

void SpdLog::v(const char *format, ...)
{
    if(!logger)
        return;
    char logbuf[2048];
    va_list ap;
    va_start(ap, format);
    vsprintf(logbuf, format, ap);
    va_end(ap);
    logger->trace("{}", logbuf);
}